home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / human interface toolbox / addresmenu7.1 / addresmenu7.1.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  36.6 KB  |  936 lines

  1. /*
  2.     File:        AddResMenu7.1.c
  3.  
  4.     Contains:    There is a small cosmetic bug in System 7.1 (a bug?  Can't even imagine the idea!).
  5.  
  6.                 AddResMenu will not alphabatize anything but FONT resource names.
  7.  
  8.                 This is obviously not critical, since the names still show up for
  9.                 other types, but enough people have written in to DTS to indicate
  10.                 that it matters a lot.
  11.  
  12.                 So, this small sample includes a function called MyAddResMenu which you
  13.                     can use in your applications to get the same functionality as
  14.                 AddResMenu under systems before 7.1, it will get all the resource info
  15.                 and add the names to the menu you specify.
  16.  
  17.                 Have a wonderful time with it.
  18.  
  19.     Written by: C.K. Haun    
  20.  
  21.     Copyright:    Copyright © 1991-1999 by Apple Computer, Inc., All Rights Reserved.
  22.  
  23.                 You may incorporate this Apple sample source code into your program(s) without
  24.                 restriction. This Apple sample source code has been provided "AS IS" and the
  25.                 responsibility for its operation is yours. You are not permitted to redistribute
  26.                 this Apple sample source code as "Apple sample source code" after having made
  27.                 changes. If you're going to re-distribute the source, we require that you make
  28.                 it clear in the source that the code was descended from Apple sample source
  29.                 code, but that you've made changes.
  30.  
  31.     Change History (most recent first):
  32.                 7/16/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  33.                 
  34.  
  35. */
  36.  
  37. #include <Events.h>
  38. #include <TextUtils.h>
  39. #include <Sound.h>
  40. #include "AddResMenu7.1.h"
  41.  
  42. /* prototypes */
  43.  
  44. void InitalizeApp(void);
  45. void DoDiskEvents(long dinfo);                              /* hi word is error code, lo word is drive number */
  46. void DrawMain(WindowPtr drawIt);
  47. Boolean DoSelected(long val);
  48. void SizeMain(WindowPtr theWindow);
  49. void InitAEStuff(void);
  50. void DoHighLevel(EventRecord *AERecord);
  51. void DoDaCall(MenuHandle themenu, long theit);
  52. void DoDocumentClick();
  53.  
  54. pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  55. pascal OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  56. pascal OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  57. pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  58.  
  59. void SampleHelpDialog(void);
  60.  
  61. WindowPtr AddNewWindow(short theID);
  62. short HasSelectionRange(DialogPeek inputDialog);
  63. Boolean IsEditKey(char theKey, short modifiers);
  64. void AddAResourceType(void);
  65. void MyAddResMenu(ResType theType, MenuHandle theMenu, short afterItem);
  66. pascal Boolean filterIt(DialogPtr inputDialog, EventRecord *myDialogEvent, short *theDialogItem);
  67. ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem);
  68. void CleanUpMetaChars(Str255 theString);
  69. void NilProc(void);
  70. Boolean TabRetEsc(DialogPtr inputDialog, EventRecord *myDialogEvent, short *theDialogItem);
  71. /* one external */
  72. #ifdef applec
  73. extern void _DataInit();                                    /* this is the C initialization code */
  74. #endif
  75.  
  76. /* globals */
  77. Boolean gQuit, gInBackground;
  78. unsigned long gMySleep;
  79. ProcessSerialNumber gOurSN;
  80. short gHelpItem;
  81. ModalFilterUPP gModalFilterUPP;
  82.  
  83. void main(void)
  84. {
  85.     EventRecord myEventRecord;
  86.     WindowPtr twindow;
  87.     short fHit;
  88.     windowCHandle tempWCH;
  89.     
  90.     #ifdef applec
  91.     UnloadSeg((Ptr)_DataInit);                              /* throw out setup code */
  92.     #endif
  93.     
  94.     InitalizeApp();
  95.     do {
  96.         
  97.         WaitNextEvent(everyEvent, &myEventRecord, gMySleep, nil);
  98.         switch (myEventRecord.what) {
  99.             case nullEvent:
  100.                 /* no nul processing in this sample */
  101.                 break;
  102.             case updateEvt:
  103.                 /* always check to see if it's my window */
  104.                 /* this may not seem necessary under 7.0, where it's unlikely or impossible for */
  105.                 /* a DA to be in your layer, but there are others*/
  106.                 /* who can stick themselves into your window list, */
  107.                 /* BalloonWriter comes quickly to mind */
  108.                 
  109.                 if (((WindowPeek)myEventRecord.message)->windowKind == kMyDocumentWindow) {
  110.                     tempWCH = (windowCHandle)GetWRefCon((WindowPtr)myEventRecord.message);
  111.                     (ProcPtr)((*tempWCH)->drawMe)((WindowPtr)myEventRecord.message);
  112.                 }
  113.                 break;
  114.             case mouseDown:
  115.                 /* first see where the hit was */
  116.                 fHit = FindWindow(myEventRecord.where, &twindow);
  117.                 
  118.                 switch (fHit) {
  119.                     Rect limitRect;
  120.                     Str255 tempString;
  121.                     long back;
  122.                     case inDesk:                            /* if they hit in desk, then the process manager */
  123.                         break;                              /* will switch us out, we don't need to do anything */
  124.                     case inMenuBar:
  125.                         DoSelected(MenuSelect(myEventRecord.where));
  126.                         break;
  127.                         
  128.                     case inSysWindow:
  129.                         
  130.                         /* pass to the system */
  131.                         SystemClick(&myEventRecord, twindow);
  132.                         break;
  133.                     case inContent:
  134.                         
  135.                         /* Handle content and control clicks here */
  136.                         
  137.                         if (FrontWindow()) {                /* don't do this unless we have a window open, silly */
  138.                             windowCHandle clicker;
  139.                             if (((WindowPeek)twindow)->windowKind == kMyDocumentWindow) {
  140.                                 
  141.                                 clicker = (windowCHandle)GetWRefCon(twindow);
  142.                                 /* jump to the content function stored for this window */
  143.                                 HLock((Handle)clicker);     /* lock it down so things don't get stupid */
  144.                                 (ProcPtr)((*clicker)->clickMe)(twindow);
  145.                                 HUnlock((Handle)clicker);       /* all done */
  146.                             }
  147.                         }
  148.                         break;
  149.                     case inDrag:
  150.                         DragWindow(twindow, myEventRecord.where, &qd.screenBits.bounds);
  151.                         break;
  152.                     case inGrow:
  153.                         /* Call GrowWindow here if you have a grow box */
  154.                         SetPort(twindow);
  155.                         limitRect = qd.screenBits.bounds;
  156.                         limitRect.top = kMinHeight;
  157.                         GetWTitle(twindow, tempString);
  158.                         /* I'm not letting the user shrink the window so */
  159.                         /* small that the title is truncated */
  160.                         limitRect.left = StringWidth(tempString) + 120;
  161.                         back = GrowWindow(twindow, myEventRecord.where, &limitRect);
  162.                         
  163.                         if (back) {
  164.                             windowCHandle tempWCH = (windowCHandle)GetWRefCon(twindow);
  165.                             Rect sizeRect = ((WindowPtr)twindow)->portRect;
  166.                             InvalRect(&sizeRect);
  167.                             sizeRect.top = sizeRect.bottom - 16;
  168.                             sizeRect.left = sizeRect.right - 16;
  169.                             EraseRect(&sizeRect);
  170.                             InvalRect(&sizeRect);
  171.                             SizeWindow(twindow, back & 0xffff, back >> 16, true);
  172.                             (ProcPtr)((*tempWCH)->sizeMe)(twindow);
  173.                         }
  174.                         InvalRect(&twindow->portRect);
  175.                         
  176.                         break;
  177.                     case inGoAway:
  178.                         /* Click in Close box */
  179.                         if (TrackGoAway(twindow, myEventRecord.where)) {
  180.                             if (((WindowPeek)twindow)->windowKind == kMyDocumentWindow)
  181.                                 (ProcPtr)((*(windowCHandle)((WindowPeek)twindow)->refCon)->closeMe)(twindow);
  182.                         }
  183.                         break;
  184.                     case inZoomIn:
  185.                     case inZoomOut:
  186.                         if (TrackBox(twindow, myEventRecord.where, fHit)) {
  187.                             windowCHandle tempWCH = (windowCHandle)GetWRefCon(twindow);
  188.                             SetPort(twindow);
  189.                             
  190.                             ZoomWindow(twindow, fHit, true);
  191.                             InvalRect(&twindow->portRect);
  192.                             if (((WindowPeek)twindow)->windowKind == kMyDocumentWindow)
  193.                                 (ProcPtr)((*tempWCH)->sizeMe)(twindow);
  194.                         }
  195.                 }
  196.             case mouseUp:
  197.                 /* don't care */
  198.                 break;
  199.                 /* same action for key or auto key */
  200.             case keyDown:
  201.             case autoKey:
  202.                 if (myEventRecord.modifiers & cmdKey)
  203.                     DoSelected(MenuKey(myEventRecord.message & charCodeMask));
  204.                 break;
  205.             case keyUp:
  206.                 /* don't care */
  207.                 break;
  208.             case diskEvt:
  209.                 
  210.                 /* I don't do anything special for disk events, this just passes them */
  211.                 /* to a function that checks for an error on the mount */
  212.                 DoDiskEvents(myEventRecord.message);
  213.                 break;
  214.             case activateEvt:
  215.                 
  216.                 if (myEventRecord.modifiers & activeFlag) {
  217.                     if (((WindowPeek)myEventRecord.message)->windowKind == kMyDocumentWindow) {
  218.                         
  219.                         tempWCH = (windowCHandle)GetWRefCon((WindowPtr)myEventRecord.message);
  220.                         (ProcPtr)((*tempWCH)->drawMe)((WindowPtr)myEventRecord.message);
  221.                     }
  222.                 }
  223.                 break;
  224.             case 10:
  225.                 /* don't care */
  226.                 break;
  227.             case 11:
  228.                 /* don't care */
  229.                 break;
  230.             case 15:
  231.                 switch ((myEventRecord.message >> 24) & 0x0FF) {        /* high byte of message */
  232.                     case suspendResumeMessage:              /* suspend/resume is also an activate/deactivate */
  233.                         gInBackground = (myEventRecord.message & kResumeMask) == 0;
  234.                         break;
  235.                 }
  236.                 break;
  237.             case kHighLevelEvent:
  238.                 DoHighLevel(&myEventRecord);
  239.                 break;
  240.             default:
  241.                 break;
  242.                 /* This dispatches high level events (AppleEvents, for example) */
  243.                 /* to our dispatch routine.This is NEW in the event loop for */
  244.                 /* System 7 */
  245.         }
  246.     }
  247.             while(gQuit != true);
  248.     
  249. }
  250.  
  251. /* DoDaCall opens the requested DA.It's here as a seperate routine if you'd */
  252. /* like to perform some action or just know when a DA is opened in your */
  253. /* layer.Can be handy to track memory problems when a DA is opened */
  254. /* with an Option-open */
  255. void DoDaCall(MenuHandle themenu, long theit)
  256. {
  257.     long qq;
  258.     Str255 DAname;
  259.     GetMenuItemText(themenu, theit, DAname);
  260.     qq = OpenDeskAcc((ConstStr255Param)DAname);
  261. }
  262.  
  263. /* end DoDaCall */
  264.  
  265. /* DoDiskEvents just checks the error code from the disk mount, */
  266. /* and puts up the 'Format' dialog (through DIBadMount) if need be */
  267. /* You can do much more here if you care about what disks are */
  268. /* in the drive */
  269. void DoDiskEvents(long dinfo)                               /* hi word is error code, lo word is drive number */
  270. {
  271.     short hival, loval, tommy;
  272.     Point fredpoint =  {
  273.         40, 40
  274.     };
  275.     hival = HiWord(dinfo);
  276.     loval = LoWord(dinfo);
  277.     if (hival != noErr)                                     /* something happened */ {
  278.         tommy = DIBadMount(fredpoint, dinfo);
  279.     }
  280. }
  281.  
  282. /* draws my window.Pretty simple */
  283. void DrawMain(WindowPtr drawIt)
  284. {
  285.     RgnHandle tempRgn;
  286.     Rect scratchRect;
  287.     BeginUpdate(drawIt);
  288.     SetPort(drawIt);
  289.     scratchRect = drawIt->portRect;
  290.     scratchRect.top = scratchRect.bottom - 15;
  291.     scratchRect.left = scratchRect.right - 15;
  292.     tempRgn = NewRgn();
  293.     GetClip(tempRgn);
  294.     ClipRect(&scratchRect);
  295.     DrawGrowIcon(drawIt);
  296.     SetClip(tempRgn);
  297.     DisposeRgn(tempRgn);
  298.     
  299.     EndUpdate(drawIt);
  300. }
  301.  
  302. /* my menu action taker.It returns a Boolean which I usually ignore, but it */
  303. /* mught be handy someday */
  304. /* I usually use it in an application to determine if a keystroke was accepted */
  305. /* by a menu or whether it should be passed along to any other key acceptors */
  306. Boolean DoSelected(long val)
  307. {
  308.     short loval, hival;
  309.     Boolean returnVal = false;
  310.     loval = LoWord(val);
  311.     hival = HiWord(val);
  312.     
  313.     switch (hival) {                                        /* switch off the menu number selected */
  314.         case kAppleMenu:                                    /* Apple menu */
  315.             if (loval != 1) {                               /* if this was not About, it's a DA */
  316.                 DoDaCall(GetMenuHandle(kAppleMenu), loval);
  317.             } else {
  318.                 Alert(kAboutBox, nil);                      /* do about box */
  319.             }
  320.             returnVal = true;
  321.             break;
  322.             
  323.         case kFileMenu:                                     /* File menu */
  324.             switch (loval) {
  325.                 
  326.                 case kQuitItem:
  327.                     gQuit = true;                           /* onlyitem */
  328.                     returnVal = true;
  329.                     break;
  330.                 default:
  331.                     break;
  332.             }
  333.             break;
  334.             
  335.         case kEditMenu:
  336.             /* edit menu junk */
  337.             /* don't care */
  338.             
  339.             switch (loval) {
  340.             default:
  341.                 break;
  342.             }
  343.             break;
  344.             
  345.         case kToolsMenu:
  346.             /* add all your test stuff here */
  347.             
  348.             switch (loval) {
  349.                 case kTestMenuChooseType:
  350.                     AddAResourceType();
  351.                     break;
  352.                 default:
  353.                     break;
  354.             }
  355.             break;
  356.             
  357.         case kHMHelpMenuID:                                 /* Defined in Balloons.h */
  358.             /* I only care about this item.If anything else is returned here, I don't know what */
  359.             /* it is, so I leave it alone.Remember, the Help Manager chapter says that */
  360.             /* Apple reserves the right to add and change things in the Help menu */
  361.             if (loval == gHelpItem)
  362.                 SampleHelpDialog();
  363.             break;
  364.             
  365.     }
  366.     HiliteMenu(0);
  367.     return(returnVal);
  368. }
  369.  
  370. void DoDocumentClick()
  371. {
  372.     
  373. }
  374.  
  375. void InitAEStuff(void)
  376. {    
  377.     OSErr aevtErr = noErr;
  378.     long aLong = 0;
  379.     Boolean gHasAppleEvents = false;
  380.     /* Check this machine for AppleEvents.  If they are not here (ie not 7.0)
  381.     *   then we exit */
  382.     gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &aLong) == noErr);
  383.     /* The following series of calls installs all our AppleEvent Handlers.
  384.     *   These handlers are added to the application event handler list that 
  385.     *   the AppleEvent manager maintains.  So, whenever an AppleEvent happens
  386.     *   and we call AEProcessEvent, the AppleEvent manager will check our
  387.     *   list of handlers and dispatch to it if there is one.
  388.     */
  389.     if (gHasAppleEvents) {
  390.          aevtErr = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, 
  391.              NewAEEventHandlerProc(AEOpenHandler),0, false);
  392.              if (aevtErr)  ExitToShell();
  393.  
  394.          aevtErr = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, 
  395.              NewAEEventHandlerProc(AEOpenDocHandler),0, false);
  396.              if (aevtErr)  ExitToShell();
  397.  
  398.          aevtErr = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, 
  399.              NewAEEventHandlerProc(AEQuitHandler), 0, false);
  400.              if (aevtErr)  ExitToShell();
  401.  
  402.          aevtErr = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, 
  403.              NewAEEventHandlerProc(AEPrintHandler),0, false);
  404.              if (aevtErr)  ExitToShell();
  405.          
  406.        } 
  407.     else ExitToShell();
  408.     
  409. }
  410. /* end InitAEStuff */
  411.  
  412. /* I'm not doing error handling in this sample for clarities sake, you should. Hah, */
  413. /* easy for me to say, huh? */
  414. void DoHighLevel(EventRecord *AERecord)
  415. {
  416.     OSErr myErr;
  417.     myErr = AEProcessAppleEvent(AERecord);
  418.     
  419. }
  420.  
  421. /* end DoHighLevel */
  422.  
  423. /* This is the standard Open Application event.*/
  424. pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  425. {
  426.     WindowPtr myWindow;
  427.  
  428. #pragma unused (messagein,reply,refIn)
  429.     /* we of course don't do anything here in this simple app */
  430.     /* except open our window */
  431.     myWindow = AddNewWindow(kDocWindowResID);
  432.     
  433.     return(noErr);
  434. }
  435.  
  436. /* end AEOpenHandler */
  437.  
  438. /* Open Doc, opens our documents.Remember, this can happen at application start AND */
  439. /* anytime else.If your app is up and running and the user goes to the desktop, hilites one */
  440. /* of your files, and double-clicks or selects Open from the finder File menu this event */
  441. /* handler will get called. Which means you don't do any initialization of globals here, or */
  442. /* anything else except open then doc.*/
  443. /* SO-- Do NOT assume that you are at app start time in this */
  444. /* routine, or bad things will surely happen to you. */
  445.  
  446. pascal OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  447. {
  448. #pragma unused (messagein,refIn,reply)
  449.     /* we of course don't do anything here */
  450.     return(errAEEventNotHandled);                           /* we have no docs, so no odoc events should come to us */
  451. }
  452.  
  453. pascal OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  454. {                                                           /* no printing handler in yet, so we'll ignore this */
  455.     /* the operation is functionally identical to the ODOC event, with the additon */
  456.     /* of calling your print routine.*/
  457. #pragma unused (messagein,refIn,reply)
  458.     /* we of course don't do anything here */
  459.     return(errAEEventNotHandled);                           /* we have no docs, so no pdoc events should come to us */
  460. }
  461.  
  462. /* Standard Quit event handler, to handle a Quit event from the Finder, for example.*/
  463. /* ••••• DO NOT CALL EXITTOSHELL HERE ••••• or you will never have a happy life.*/
  464. /* OK, it's a few months after I wrote that comment, and I've seen a lot of code */
  465. /* come through DTS that calls ExitToShell from quit handlers.Let me explain... */
  466. /* When an AppleEvent Handler is called (like this quit handler) you are ALMOST */
  467. /* 100% in your application world.A5 is right, you can call any toolbox function, */
  468. /* you can call your own routines, everything _seems_ like you are in complete*/
  469. /* control.Well, almost but not quite.The routine has been dispatch to from the */
  470. /* AppleEvent Manager's space, so you _must_ return to that at some point! */
  471. /* Which is why you can't call ETS from here.When you call ExitToShell from an */
  472. /* AE Handler, the most likely thing that happens is the FInder quits, and your*/
  473. /* application keeps running.Which ain't what you want, y'know? */
  474. /* so, DON'T CALL EXITTOSHELL FROM AN APPLEEVENT HANDLER!!!!!!!!!!!!!! */
  475. pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  476. {
  477. #pragma unused (messagein,refIn,reply)
  478.     gQuit = true;
  479.     return(noErr);
  480. }
  481.  
  482. /* This is my sample help dialog.Does not do anything, expand as you need */
  483. void SampleHelpDialog(void)
  484. {
  485.     DialogPtr tdial = GetNewDialog(kSampHelp, nil, (WindowPtr)-1);
  486.     short itemhit = 0;
  487.     while (itemhit != 1) {
  488.         ModalDialog(nil, &itemhit);
  489.     }
  490.     DisposeDialog(tdial);
  491. }
  492.  
  493. WindowPtr AddNewWindow(short theID)
  494. {
  495.     windowCHandle setControls;
  496.     WindowPtr tempWP;
  497.     short cnt = 0;
  498.     tempWP = GetNewWindow(theID, 0, (WindowPtr)-1);         /* get a new window */
  499.     ((WindowPeek)tempWP)->windowKind = kMyDocumentWindow;       /* mark it as my document window */
  500.     setControls = (windowCHandle)NewHandleClear(sizeof(windowControl));     /* add our control structure to it */
  501.     SetWRefCon(tempWP, (long)setControls);                  /* stop stuffing refCon directly <ckh 1.0.3> */
  502.     HLock((Handle)setControls);                             /* lock it down while we fill it*/
  503.     
  504.     /* add pointers to our procedures for drawing, saving, and closing */
  505.     /* This way, all I need is one dispatch point for drawing, closing */
  506.     /* or whatever, I don't have to case off the window kind to go to the*/
  507.     /* correct routine.Kinda like object-oriented programming, but I won't */
  508.     /* admit that. */
  509.     (*setControls)->drawMe = (ProcPtr)DrawMain;
  510.     (*setControls)->clickMe = (ProcPtr)DoDocumentClick;
  511.     (*setControls)->sizeMe = (ProcPtr)SizeMain;
  512.     (*setControls)->generalData = NewHandle(0);
  513.     return(tempWP);
  514. }
  515.  
  516. void SizeMain(WindowPtr theWindow)
  517. {
  518.     WindowPtr tempWP;
  519.     GetPort(&tempWP);
  520.     InvalRect(&theWindow->portRect);
  521.     SetPort(tempWP);
  522. }
  523.  
  524. void NilProc(void)
  525. {
  526.     
  527. }
  528.  
  529. /* AddAResourceType asks for the resource type to add to the menu */
  530. /* it preflights to see if at least one exists, then passes of to MyAddResMenu */
  531. void AddAResourceType(void)
  532. {
  533.     Rect tempRect;
  534.     short tempItem;
  535.     Handle tempHandle;
  536.     Str15 myStr;
  537.     ResType theType;
  538.     short hitItem;
  539.     DialogPtr myDialog = GetNewDialog(kResTypeDialog, nil, (WindowPtr)-1);
  540.     
  541.     /* New System 7 dialog manager calls, see tech note #304 */
  542.     /* interface to these calls is in AddResMenu7.1.h */
  543.     SetDialogDefaultItem(myDialog, ok);
  544.     SetDialogCancelItem(myDialog, cancel);
  545.     SetDialogTracksCursor(myDialog, true);
  546.     
  547.     do {
  548.         ModalDialog(gModalFilterUPP, &hitItem);
  549.     }
  550.             while (hitItem != ok && hitItem != cancel);
  551.     
  552.     if (hitItem == ok) {
  553.         
  554.         /* get the type and hammer it */
  555.         GetDialogItem(myDialog, kResTypeEditLine, &tempItem, &tempHandle, &tempRect);
  556.         GetDialogItemText(tempHandle, myStr);
  557.         
  558.         /* make sure there are 4 characters here, please */
  559.         if (myStr[0] == 4) {
  560.             BlockMove((Ptr)&myStr[1], (Ptr)&theType, sizeof(theType));
  561.             /* reality check to see if there are any of these at this time */
  562.             tempItem = Count1Resources(theType);
  563.             if (tempItem) {
  564.                 /* clear the menu out before I add new things*/
  565.                 tempItem = CountMItems(GetMenuHandle(kToolsMenu));
  566.                 
  567.                 /* I want to add below the dividing line */
  568.                 tempItem -= kTestMenuDivider;
  569.                 while (tempItem) {
  570.                     DeleteMenuItem(GetMenuHandle(kToolsMenu), kTestMenuDivider + 1);
  571.                     
  572.                     tempItem--;
  573.                 }
  574.                 
  575.                 /* call my routine */
  576.                 MyAddResMenu(theType, GetMenuHandle(kToolsMenu), kTestMenuDivider);
  577.             } else {
  578.                 /* yell because there are none of that type around */
  579.                 ParamText((ConstStr255Param)myStr, (ConstStr255Param)"", (ConstStr255Param)"", (ConstStr255Param)"");
  580.                 CautionAlert(kNoneOfThatType, nil);
  581.             }
  582.         }
  583.     }
  584.     DisposeDialog(myDialog);
  585.     
  586. }
  587.  
  588. /* MyAddResMenu does, basically, what AddResmenu does, it does an */
  589. /* "insert sort" (one of the Comp. Sci. types around here told me to call it that) */
  590. /* of the names of the resources.It uses IUCompString for */
  591. /* International Reasons (KFJC 89.7, 12-3 Sundays) */
  592. /* The only thing it really does differently is includes items that don't have */
  593. /* names by including the 'unnamedX' string. */
  594. /* Also notice that, since I'm using InsertMenuItem I have to parse the*/
  595. /* name string and take out any menu manager meta-characters before I insert things */
  596. /* so I don't get strange command keys from a name like "Alert/Warning 1" */
  597.  
  598. void MyAddResMenu(ResType theType, MenuHandle theMenu, short afterItem)
  599. {
  600.     short originalCount = afterItem;
  601.     short resourceCount = Count1Resources(theType);
  602.     short index = 1;
  603.     short unnamedCount = 0;
  604.     short qq;
  605.     ResType theIndexType;
  606.     short theID;
  607.     Str255 theName;
  608.     Str32 unusedWord;
  609.     Str255 tempString;
  610.     Handle tempHandle;
  611.     Boolean oldResLoad = *((Boolean *)0xA5E);
  612.     Boolean addedIt = false;
  613.     
  614.     GetIndString(unusedWord, kGenStrings, kUnnamedString);
  615.     SetResLoad(false);                                      /* don't want to load the resources */
  616.     do {
  617.         tempHandle = Get1IndResource(theType, index);
  618.         theName[0] = 0;
  619.         GetResInfo(tempHandle, &theID, &theIndexType, theName);
  620.         /* Check the name, if no name tell it so... */
  621.         if (theName[0] == 0) {
  622.             BlockMove((Ptr)&unusedWord, (Ptr)&theName, unusedWord[0] + 1);
  623.             NumToString((long)unnamedCount, tempString);
  624.             if ((theName[0] + tempString[0]) < 254) {
  625.                 BlockMove((Ptr)&tempString[1], (Ptr)(&theName[1] + theName[0]), tempString[0]);
  626.                 theName[0] += tempString[0];
  627.             }
  628.             unnamedCount++;
  629.         }
  630.         CleanUpMetaChars(theName);
  631.         /* here's where you sort in the menu items */
  632.         /* it goes roughly like.... */
  633.         for (qq = afterItem + 1; qq < CountMItems(theMenu) + 1; qq++) {
  634.             GetMenuItemText(theMenu, qq, tempString);
  635.             if (IUCompString(theName, tempString) == -1) {
  636.                 /* new string is less than an existing name */
  637.                 /* so insert it before it */
  638.                 InsertMenuItem(theMenu, theName, qq - 1);
  639.                 addedIt = true;
  640.                 break;                                      /* leave the 'for' loop */
  641.             }
  642.         }
  643.         /* If it didn't sort in, just add it to the end of the menu */
  644.         if (!addedIt)
  645.             InsertMenuItem(theMenu, theName, CountMItems(theMenu) + 1);
  646.         addedIt = false;
  647.         index++;
  648.     }
  649.             while (index <= resourceCount);
  650.     SetResLoad(oldResLoad);
  651. }
  652.  
  653. /* Some dialog filtering things */
  654. /* TabRetEsc toggles the cancel or OK button for keystrokes, and */
  655. /* treats a Tab press as selecting the whole edit line contents */
  656.  
  657. Boolean TabRetEsc(DialogPtr inputDialog, EventRecord *myDialogEvent, short *theDialogItem)
  658. {
  659.     Boolean returnValue = false;
  660.     unsigned long tilticks;
  661.     WindowPtr tempWindowPtr;
  662.     char theKey = myDialogEvent->message &charCodeMask;
  663.     GetPort(&tempWindowPtr);
  664.     SetPort(inputDialog);
  665.     switch (theKey) {
  666.         case kReturnKey:
  667.         case kEnterKey:                                     /* enter key */
  668.             /* This filters for Return or Enter as item 1, and Esc as item 2 */
  669.             *theDialogItem = ok;                            /* change whatever the current item is to the OK item */
  670.             /* now we need to invert the button */
  671.             HiliteControl(SnatchHandle(inputDialog, ok), 10);
  672.             Delay(8, &tilticks);                            /* wait about 8 ticks so they can see it */
  673.             HiliteControl(SnatchHandle(inputDialog, ok), false);
  674.             returnValue = true;
  675.             break;
  676.             /* This filters the escape key as the same as item 2 (the canx button, usually ) */
  677.         case kEscKey:
  678.             *theDialogItem = cancel;
  679.             HiliteControl(SnatchHandle(inputDialog, cancel), 10);
  680.             Delay(8, &tilticks);                            /* wait about 8 ticks so they can see it */
  681.             HiliteControl(SnatchHandle(inputDialog, cancel), false);
  682.             returnValue = true;
  683.             break;
  684.         case kTabKey:
  685.             /* I'm filtering the tab key here so a tab selects all the */
  686.             /* text in the edit line, as a convinience */
  687.             SelectDialogItemText(inputDialog, kResTypeEditLine, 0, 5);
  688.             returnValue = true;                             /* don't allow edit line swaps */
  689.             break;
  690.     }
  691.     SetPort(tempWindowPtr);
  692.     
  693.     return(returnValue);
  694.     
  695. }
  696.  
  697. /* Main dialog filter */
  698. pascal Boolean filterIt(DialogPtr inputDialog, EventRecord *myDialogEvent, short *theDialogItem)
  699. {
  700.     
  701.     Boolean returnVal = false;
  702.     ModalFilterUPP theModalProc;
  703.     char theKey;
  704.     Rect tempRect;
  705.     short tempItem;
  706.     Handle tempHandle;
  707.     char tempKey;
  708.     Str255 myStr;
  709.     long offset;
  710.     short selection;
  711.     long scrapLen;
  712.     short resultLen;
  713.     Boolean wasAKey = false;
  714.     if ((myDialogEvent->what == updateEvt) && (myDialogEvent->message != (UInt32)inputDialog)) {
  715.         /* May be a pending update event for another window, handle it so */
  716.         /* other layers get time */
  717.         windowCHandle tempWCH;
  718.         WindowPtr theWindow = (WindowPtr)myDialogEvent->message;
  719.         /* draw my window if it's really mine */
  720.         if (((WindowPeek)theWindow)->windowKind == kMyDocumentWindow) {
  721.             tempWCH = (windowCHandle)GetWRefCon(theWindow);
  722.             (ProcPtr)((*tempWCH)->drawMe)((WindowPtr)theWindow);
  723.             
  724.             *theDialogItem = 0;
  725.             returnVal = true;
  726.         }
  727.     } else {
  728.         wasAKey = (myDialogEvent->what == keyDown) || (myDialogEvent->what == autoKey);
  729.         
  730.         if ((wasAKey)) {
  731.             /* first check on the Big Three, tab, return, and escape */
  732.             if (!(returnVal = TabRetEsc(inputDialog, myDialogEvent, theDialogItem))) {
  733.                 
  734.                 /* not one of those, see if this keystroke will fit */
  735.                 /* in the edit line (restricted to 4 characters for a ResType) */
  736.                 
  737.                 /* Here I'm seeing if anything is selected, and getting the length */
  738.                 /* of the desk scrap in case the user presses */
  739.                 /* Copy or Paste keys */
  740.                 
  741.                 selection = HasSelectionRange((DialogPeek)inputDialog);
  742.                 scrapLen = GetScrap(nil, 'TEXT', &offset);
  743.                 
  744.                 GetDialogItem(inputDialog, kResTypeEditLine, &tempItem, &tempHandle, &tempRect);
  745.                 GetDialogItemText(tempHandle, myStr);
  746.                 
  747.                 /* calculate the result of adding the scrap to the current record.We use */
  748.                 /* this in a few places here */
  749.                 resultLen = myStr[0] + (scrapLen - selection);
  750.                 
  751.                 theKey = myDialogEvent->message & charCodeMask;
  752.                 tempKey = theKey;
  753.                 if (tempKey >= 0x61 && tempKey <= 0x7a)
  754.                     tempKey -= 0x20;
  755.                 
  756.                 if (myStr[0] > 3) {                         /* over 4, see what it is */
  757.                     
  758.                     if (IsEditKey(theKey, myDialogEvent->modifiers)) {
  759.                         /* it was an editing key, but it MAY be a command-V. */
  760.                         /* If it's a command-V then we won't allow it UNLESS */
  761.                         /* there is a slection range AND the new data won't overrun things */
  762.                         if ((tempKey == 'V') && (myDialogEvent->modifiers & cmdKey)) {
  763.                             
  764.                             /* this was a paste.check selection range and scrap len*/
  765.                             if (resultLen < 4) {
  766.                                 returnVal = false;          /* net result is4 or less */
  767.                             } else {
  768.                                 SysBeep(1);
  769.                                 returnVal = true;
  770.                             }
  771.                         } else {
  772.                             returnVal = false;              /* don't filter out editing keys */
  773.                         }
  774.                     } else {
  775.                         /* One more check (this can get complicated, huh?) */
  776.                         /* We now look to see if there is a selection range.If there */
  777.                         /* is a range of 1 or more characters, then the one character they are entering */
  778.                         /* now will replace that, and we'll end up with _less_ than 4 (or equal) */
  779.                         /* to do this, we have to get the TERecord out of the dialog.*/
  780.                         /* I'm going to do this in a seperate function */
  781.                         if (selection == nil) {
  782.                             SysBeep(1);                     /* complain a little */
  783.                             returnVal = true;               /* tell the dialog manager that we handled this already and */
  784.                             /* it doesn't have to, so the keystroke will _not_ get */
  785.                             /* added to the edit line */
  786.                         }
  787.                     }
  788.                 } else {
  789.                     /* even if we're less than 4 currently, a Command-V (paste) could put us over */
  790.                     /* so check it out */
  791.                     
  792.                     if ((tempKey == 'V') && (myDialogEvent->modifiers & cmdKey)) {
  793.                         
  794.                         /* Gettting the scrap with a nil handle, which does not give us data, just */
  795.                         /* returns the size */
  796.                         if (resultLen > 3) {
  797.                             SysBeep(1);                     /* complain a little */
  798.                             returnVal = true;               /* tell the dialog manager that we handled this already and */
  799.                             
  800.                         }
  801.                     }
  802.                 }
  803.             }
  804.         }
  805.     }
  806.     if (!returnVal) {
  807.         
  808.         OSErr myErr = GetStdFilterProc(&theModalProc);
  809.         if (myErr == noErr)
  810.             returnVal = CallModalFilterProc(theModalProc, inputDialog, myDialogEvent, theDialogItem);
  811.     }
  812.     return(returnVal);
  813. }
  814.  
  815. short HasSelectionRange(DialogPeek inputDialog)
  816. {
  817.     TEHandle theTERecord = inputDialog->textH;
  818.     short returnVal = (*theTERecord)->selEnd -(*theTERecord)->selStart;
  819.     
  820.     return(returnVal);
  821. }
  822.  
  823. /* end HasSelectionRange */
  824.  
  825. /* a little utility to see if the current key is an edit-type key */
  826. Boolean IsEditKey(char theKey, short modifiers)
  827. {
  828.     register qq;
  829.     Boolean returnVal = false;
  830.     char editChars[] =  {
  831.         kLeftArrow, kUpArrow, kRightArrow, kDownArrow, kBackSpace, kEscKey
  832.     };
  833.     char commandEdits[] =  {
  834.         'C', 'V', 'P'
  835.     };
  836.     for (qq = 0; qq < sizeof(editChars) / sizeof(char); qq++) {
  837.         if (theKey == editChars[qq])
  838.             returnVal = true;
  839.     }
  840.     if (returnVal != true && (modifiers & cmdKey)) {
  841.         /* check for XCP */
  842.         /* Do you want me to use 'toupper()'?What! And link in all of StdLib! aggggg */
  843.         if (theKey >= 0x61 && theKey <= 0x7a)
  844.             theKey -= 0x20;
  845.         for (qq = 0; qq < sizeof(commandEdits) / sizeof(char); qq++) {
  846.             if (theKey == commandEdits[qq])
  847.                 returnVal = true;
  848.         }
  849.     }
  850.     return(returnVal);
  851. }
  852.  
  853. /* end IsEditKey */
  854.  
  855. /* Gets the ControlHandle for the item you want in the dialog box thebox.*/
  856. /* Handy for setting checkboxes and radio buttons */
  857. /* This is the _most_ copied routine from this file */
  858. ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem)
  859. {
  860.     short itemtype;
  861.     Rect itemrect;
  862.     Handle thandle;
  863.     
  864.     GetDialogItem(thebox, theGetItem, &itemtype, &thandle, &itemrect);
  865.     return((ControlHandle)thandle);
  866. }
  867.  
  868. /* end SnatchHandle */
  869.  
  870. void CleanUpMetaChars(Str255 theString)
  871. {
  872.     char metaKeys[] =  {
  873.         ';', '^', '!', '<', '/', '('
  874.     };
  875.     register qq, ii;
  876.     
  877.     qq = theString[0];
  878.     while (qq) {
  879.         for (ii = 0; ii < sizeof(metaKeys) / sizeof(char); ii++) {
  880.             if (theString[qq] == metaKeys[ii])
  881.                 theString[qq] = '•';                         /* replace with a Spot */
  882.         }
  883.         qq--;
  884.     }
  885. }
  886.  
  887.  
  888. void InitalizeApp(void)
  889. {
  890.     Handle myMenu;
  891.     MenuHandle helpHandle, appleMenuHandle;
  892.     StringHandle helpString;
  893.     short count;
  894.     long vers;
  895.     MaxApplZone();
  896.     InitGraf((Ptr)&qd.thePort);
  897.     InitFonts();
  898.     InitWindows();
  899.     InitMenus();
  900.     TEInit();
  901.     InitDialogs(nil);
  902.     InitCursor();
  903.     /* Check system version */
  904.     Gestalt(gestaltSystemVersion, &vers);
  905.     vers = (vers >> 8) & 0xf;                               /* shift result over and mask out major version number */
  906.     if (vers < 7) {
  907.         StopAlert(kBadSystem, nil);
  908.         ExitToShell();
  909.     }
  910.     InitAEStuff();
  911.     
  912.     /* set up the UPP for our dialog filter proc */
  913.     gModalFilterUPP = NewModalFilterProc(filterIt);
  914.   
  915.     /* set up my menu junk */
  916.     myMenu = GetNewMBar(kMBarID);
  917.     SetMenuBar(myMenu);
  918.     appleMenuHandle = GetMenuHandle(kAppleMenu);
  919.     AppendResMenu(appleMenuHandle, 'DRVR');
  920.     
  921.     /* now install my Help menu item in the Help Manager's menu */
  922.     HMGetHelpMenuHandle(&helpHandle);                       /* Get the Hlpe menu handle */
  923.     count = CountMItems(helpHandle);                        /* How many items are there? */
  924.     helpString = GetString(kHelpString);                    /* get my help string */
  925.     DetachResource((Handle)helpString);                             /* detach it */
  926.     HNoPurge((Handle)helpString);
  927.     MoveHHi((Handle)helpString);
  928.     HLock((Handle)helpString);
  929.     InsertMenuItem(helpHandle, (ConstStr255Param)helpString, count + 1);       /* insert my item in the Help menu */
  930.     gHelpItem = CountMItems(helpHandle);                    /* The number of the item */
  931.     
  932.     DrawMenuBar();
  933.     GetCurrentProcess(&gOurSN);                             /* Get our process serial number for later use, if needed */
  934.     
  935. }
  936.